'''
@author yayi2456@163.com

DS_init文件用于初始化部分系统参数。
包括区块大小、区块id、区块热度排序、节点间通信开销、模拟出块区间。
'''

import numpy as np
import sys
import json

# datasize of blocksize
FILESIZENAME='E:/CUB/bh.dat/blocksize-654000.csv'
# 节点id文件存储位置
BLOCKID_FN='E:/CUB/bh.dat/blockid.txt'
# 节点热度排序文件存储位置，其中是一个list，list(i)记录了编号为i的区块的排序（从0开始编号）
CONSTANTRANK_FN='E:/CUB/bh.dat/constantrank.txt'
# 模拟出块区间
beginID=654000
endID=beginID+1000

# list of int，BLOCK_ID[i]中存储编号为i的区块对应的id。
BLOCK_ID=[]
# CONSTANT_RANDK 是一个字典，其中保存了每一个区块排序和区块编号（从0开始）的对应关系，
# 其中，key是区块的热度排序，value是区块的编号。
CONSTANT_RANK={}

def load_blocksizes(bID,eID):
    """(int,int) -> (list of float, float)

    Return blocksizes of blocks whose height are between [bgeinID,endID) base on file FILESIZENAME.
    Return total size of blocks whose height is in [beginID,endID)
    """
    global beginID
    global endID
    beginID=bID
    endID=eID
    blocksizes=[]

    # size sum of all blocks between [beginID,endID)
    storage_of_all_blocks=0

    with open(FILESIZENAME,'r') as size_file:
        for size_line in size_file:
            size_line_item=size_line.split(',')
            # get block height
            blockID=int(size_line_item[0])
            # skip blocks lower than beginID and no lower than endID
            if blockID<beginID:
                continue
            if blockID>=endID:
                break
            block_size=float(size_line_item[1])/1000000
            blocksizes.append(block_size)
            # sum this size up to storage_of_all_blocks
            storage_of_all_blocks+=block_size

    return blocksizes,storage_of_all_blocks

def load_blockids(size):
    '''
    loads blocks' id and put the first `size` of them into `BLOCK_ID`, the global param.
    '''
    global BLOCK_ID
    with open(BLOCKID_FN,'r')as fr:
        for line in fr:
            BLOCK_ID=json.loads(line)
            break
    BLOCK_ID=BLOCK_ID[:size]

def load_rank(size):
    '''
    loads the relationship between block number and its rank of popularity,
    stores the relationship into `CONSTANT_RANDK`, the global param.
    '''
    global CONSTANT_RANK
    BLOCK_RANK=[]
    with open(CONSTANTRANK_FN,'r')as fr:
        for line in fr:
            BLOCK_RANK=json.loads(line)
            break
    i=0
    for brank in BLOCK_RANK:
        if brank<size:
            CONSTANT_RANK[brank]=i
            i+=1


def generate_communication_cost(nodes_num, distribution_type):
    """(int,str) -> list of list of float

    Return communication cost between every 2 nodes generated randomly in normal distribution.

    2 types are allowed:
    'normal'/'1'
    """

    communication_cost=[]

    # generate communication cost randomly
    try:
        # normal distribution
        if distribution_type=='normal':
            mu=1
            sigma=0.5

            # communication_cost=np.absolute(np.random.normal(mu,sigma,[nodes_num,nodes_num]))
            communication_cost=[[0.9283573 , 1.20546818, 0.73509698, 1.88864734, 1.29204335,
        2.09526447, 1.5963019 , 0.02879965, 0.02458762, 0.91872697],
       [0.30036054, 1.00466097, 1.52191513, 0.65414875, 1.50644343,
        0.68382484, 0.92965741, 0.42839557, 1.17236144, 1.02996051],
       [0.56822564, 1.27541919, 0.61683779, 0.84236014, 1.0612637 ,
        0.92658329, 0.99121881, 1.81738219, 1.78517851, 0.24705094],
       [1.79836131, 1.09191752, 1.60516537, 0.37575595, 1.38438759,
        1.63279625, 0.70583861, 1.06731513, 1.42392138, 0.7188484 ],
       [1.03360349, 0.18936742, 0.59310497, 0.50183122, 1.1486868 ,
        1.05833852, 1.38323434, 1.13598478, 1.16539371, 0.96001515],
       [0.93136753, 1.12780837, 0.13849183, 1.14214214, 0.60152085,
        0.55402053, 1.10870503, 0.67730834, 0.68433858, 0.66241989],
       [1.79465379, 0.80143361, 0.98104521, 0.30108855, 1.00392018,
        0.94334858, 0.67497941, 0.8915002 , 1.36297052, 0.63732797],
       [0.76799253, 0.58418479, 0.93061772, 1.50013164, 0.8554365 ,
        1.77693385, 0.64691308, 0.82144779, 0.4348138 , 1.91490114],
       [0.98391884, 1.19110244, 1.01538815, 0.69359769, 0.53632453,
        0.97916297, 1.01081265, 0.38186164, 0.44921611, 1.96850188],
       [1.6611757 , 0.12190398, 1.32284431, 1.04920968, 0.34622065,
        0.11826715, 2.28277831, 0.37742129, 1.38527299, 0.95568288]]
        # each pair of nodes communicate at 1 cost
        elif distribution_type=='1':
            communication_cost=np.absolute(np.random.normal(1,1,[nodes_num,nodes_num]))
        else:
            sys.exit(-2)
    except:
        print('INVALID DISTRIBUTION TYPE! must be \'normal\' or \'1\'. distribution_type=\'1\' set.')
        communication_cost=np.absolute(np.random.normal(1,1,[nodes_num,nodes_num]))
    # nodes have no communication cost with itself
    for i in range(nodes_num):
        communication_cost[i][i]=0
    # lower communication cost by 5 times
    communication_cost=np.array(communication_cost)/5
    
    return communication_cost


def getBlockID():
    return BLOCK_ID
def getConstantRank():
    return CONSTANT_RANK
def getBeginID():
    return beginID
def getEndID():
    return endID
